﻿#pragma once

#include "DataObject.h"
#include "Logging.h"
#include "Object.h"
#include "Timer.h"

class Application;
class Mesh;
class System : public Object
{
public:
  System(const Configuration& cfg);
  virtual ~System(){};

  virtual void Init();
  virtual void InitVariable() {}
  virtual void Evolve() = 0;

  template<typename T>
  void AddCellVariable(const std::string& name)
  {
    _data_set.AddCellField(name, ArrayHandle<T>{});
  }

  template<typename T>
  void AddPointVariable(const std::string& name)
  {
    _data_set.AddPointField(name, ArrayHandle<T>{});
  }

  template<typename T>
  ArrayHandle<T> GetVariableArray(const std::string& name)
  {
    try
    {
      return _data_set.GetField(name).GetData().AsArrayHandle<ArrayHandle<T>>();
    }
    catch (const std::exception& e)
    {
      Error(e.what());
    }
  }

  const auto& GetDateSet() const { return this->_data_set; }

  auto& GetMesh() { return this->_mesh; }
  auto& App() { return this->_app; }
  auto& GetTimer() { return this->_timer; }
  /// <summary>
  /// bc_pair通过参数文件读取
  /// type = FarField
  /// boundary = 'far1, far2'
  /// </summary>
  /// <param name="bc_pair"></param>
  void AddBoundaryCondition(const std::pair<std::string, std::vector<std::string>>& bc_pair);

protected:
  DataSet _data_set;
  Application& _app;

  /// <summary>
  /// boundary_type -> bc_id, 在子类的构造函数中填充，
  /// 如：_bnd_type_id["FarField"] = 2; _bnd_type_id["Wall"] = 3;
  /// </summary>
  std::map<std::string, UInt8> _bnd_type_id;  // boundary_type -> bc_id

  /// <summary>
  /// 网格中的side set name --> bc_id，由`AddBoundaryCondition(const std::pair<std::string, std::vector<std::string>>& bc_pair)` 填充
  /// </summary>
  std::map<std::string, UInt8> _bnd_name_id;  // boundary_name -> bc_id
  Mesh& _mesh;
  Timer _timer;
};
